package com.fadis.data;

import com.fadis.data.base.StringSet;
import com.fadis.data.set.RandomAccessHashSet;
import com.fadis.utils.FadisUtils;

import java.util.ArrayList;
import java.util.List;

public class FSet {


    /**
     *
     * @param set
     * @param members
     * @return 被添加到集合中的新元素的数量
     */
    public static int sadd(StringSet set, String... members) {
        int addCount = 0;
        for (String s: members){
            if(set.add(s)) addCount += 1;
        }
        return addCount;
    }


    /**
     * 
     * @param set
     * @param members
     * @return 被成功移除的元素的数量
     */
    public static int srem(StringSet set, String... members) {
        int remCount = 0;
        for (String s: members){
            if(set.remove(s)) {
                remCount += 1;
            }
        }
        return remCount;
    }

    /**
     * 移除并返回集合中的一个随机元素。
     * @param set
     * @return 无或空返回null
     */
    public static String spop(RandomAccessHashSet<String> set) {
        List<String> list = spop(set, 1, true);
        if(list.size() > 0) return list.get(0);
        else return null;
    }

    /**
     * 移除并返回集合中的count个随机元素。
     * @param set
     * @param count
     * @return 无或空返回空集合
     */
    public static StringSet spop(RandomAccessHashSet<String> set, int count) {
        StringSet set2 = new StringSet();
        List<String> list = spop(set, count, true);
        set2.addAll(list);
        return set2;
    }

    /**
     * 移除并返回集合中的count个随机元素。
     * @param set
     * @param count  整数表示不重复，负数表示允许重复
     * @return 无或空返回空集合
     */
    private static List<String> spop(RandomAccessHashSet<String> set, int count, boolean remove) {
        List<String> set2 = new ArrayList<>();
        if(set == null) return set2;
        if(set.isEmpty()) return set2;

        boolean allowRepeat = count < 0;
        int maxCount = Math.min(Math.abs(count), set.size());

        StringSet popped = new StringSet();

        while(popped.size() < maxCount){
            if(set.size() == 0) break;
            int randomIndex = FadisUtils.randomInt(0, set.size() - 1);
            String item = set.get(randomIndex);

            if(remove) set.remove(item);

            if(!allowRepeat && popped.contains(item)){
                continue;
            }
            popped.add(item);
        }

        set2.addAll(popped);
        return set2;
    }

    public static String srandmember(RandomAccessHashSet<String> set) {
        List<String> list = spop(set, 1, false);
        if(list.size() > 0) return list.get(0);
        else return null;
    }

    public static List<String> srandmember(RandomAccessHashSet<String> set, int count) {
        List<String> list = spop(set, count, false);
        return list;
    }

    /**
     * 把member从集合src移到dst
     * @param setSrc
     * @param setDst
     * @param member
     * @return 存在则移动成功，返回1，否则0
     */
    public static int smove(StringSet setSrc, StringSet setDst, String member) {
        if(setSrc == null) return 0;
        if(!setSrc.contains(member)) return 0;
        setSrc.remove(member);
        setDst.add(member);
        return 1;
    }

    /**
     * 返回集合 key 的基数(集合中元素的数量)。
     * @param set
     * @return 无或空返回0
     */
    public static int scard(StringSet set) {
        if(set == null) return 0;
        return set.size();
    }

    /**
     * 是否成员
     * @param set
     * @param member
     * @return
     */
    public static boolean sismember(StringSet set, String member) {
        if(set == null || set.isEmpty()) return false;
        return set.contains(member);
    }

    /**
     * 交集
     * @param sets
     * @return 新集合
     */
    public static StringSet sinter(StringSet... sets) {
        StringSet set = new StringSet();

        // 找出最小的集合【因为是要返回一个新集合，原始集合都不能修改】
        StringSet minSet = null;
        for (StringSet s: sets){
            if(minSet == null && s != null) {
                minSet = s;
            }else if(s != null && s.size() < minSet.size()){
                minSet = s;
            }
        }
        if(minSet == null || minSet.size() == 0) return set;
        set.addAll(minSet);

        for (StringSet s: sets){
            if(s != null && s != minSet){
                set.retainAll(s);
            }
        }

        return set;
    }



    /**
     * 并集
     * @param sets
     * @return 新集合
     */
    public static StringSet sunion(StringSet... sets) {
        StringSet set = new StringSet();
        for (StringSet s: sets){
            if(s != null){
                set.addAll(s);
            }
        }
        return set;
    }


    /**
     * 差集，以第一个集合为准，所有出现在第一个集合里，但没出现在其他所有集合里的元素
     * @param sets
     * @return
     */
    public static StringSet sdiff(StringSet... sets) {
        StringSet set = new StringSet();
        if(sets.length == 0) return set;
        if(sets[0] == null) return set;

        set.addAll(sets[0]);

        for (int i = 1; i < sets.length; i++) {
            set.removeAll(sets[i]);
        }
        return set;
    }

}
